"""
RedFire 网关管理器
================

统一管理多个数据源网关的生命周期，提供集中化的连接管理、
数据分发、健康监控等功能。支持动态添加和移除数据源。

特性：
- 多网关统一管理
- 自动故障转移
- 负载均衡分发
- 健康状态监控
- 动态配置更新
"""

from typing import Dict, List, Optional, Any, Callable, Set
from dataclasses import dataclass, field
from datetime import datetime
import asyncio
import logging
from contextlib import asynccontextmanager
from collections import defaultdict

from .redfire_gateway_adapter import (
    RedFireGatewayAdapter, DataSourceType, ConnectionStatus,
    MarketDataTick, MarketDataBar, ContractInfo
)
from backend.redfire_framework.core.container import RedFireContainer
from backend.redfire_framework.core.config import get_service_settings


@dataclass
class GatewayConfig:
    """网关配置"""
    name: str                            # 网关名称
    type: DataSourceType                 # 数据源类型
    enabled: bool = True                 # 是否启用
    priority: int = 1                    # 优先级(数字越小优先级越高)
    config: Dict[str, Any] = field(default_factory=dict)  # 具体配置
    
    # 健康检查配置
    health_check_interval: int = 30      # 健康检查间隔(秒)
    max_failure_count: int = 3           # 最大失败次数
    
    # 重连配置
    auto_reconnect: bool = True          # 是否自动重连
    max_reconnect: int = 10              # 最大重连次数
    reconnect_interval: int = 5          # 重连间隔(秒)


@dataclass
class GatewayStatus:
    """网关状态信息"""
    name: str
    type: DataSourceType
    status: ConnectionStatus
    connected: bool
    last_heartbeat: datetime
    failure_count: int = 0
    total_messages: int = 0
    error_messages: int = 0
    uptime: float = 0.0                  # 运行时间(秒)
    
    def to_dict(self) -> Dict[str, Any]:
        return {
            "name": self.name,
            "type": self.type.value,
            "status": self.status.value,
            "connected": self.connected,
            "last_heartbeat": self.last_heartbeat.isoformat(),
            "failure_count": self.failure_count,
            "total_messages": self.total_messages,
            "error_messages": self.error_messages,
            "uptime": self.uptime
        }


class RedFireGatewayManager:
    """
    RedFire网关管理器
    
    负责管理多个数据源网关，提供统一的数据访问接口。
    支持自动故障转移、负载均衡、健康监控等高级功能。
    """
    
    def __init__(self, service_name: str = "market-data-service"):
        """
        初始化网关管理器
        
        Args:
            service_name: 服务名称，用于获取配置
        """
        self.service_name = service_name
        self.config = get_service_settings(service_name)
        self.logger = logging.getLogger(f"redfire.gateway.manager")
        
        # 网关管理
        self._gateways: Dict[str, RedFireGatewayAdapter] = {}
        self._gateway_configs: Dict[str, GatewayConfig] = {}
        self._gateway_status: Dict[str, GatewayStatus] = {}
        
        # 订阅管理
        self._symbol_subscriptions: Dict[str, Set[str]] = defaultdict(set)  # symbol -> gateway_names
        self._gateway_subscriptions: Dict[str, Set[str]] = defaultdict(set)  # gateway_name -> symbols
        
        # 回调管理
        self._tick_callbacks: List[Callable] = []
        self._bar_callbacks: List[Callable] = []
        self._contract_callbacks: List[Callable] = []
        self._status_callbacks: List[Callable] = []
        
        # 监控任务
        self._monitoring_task: Optional[asyncio.Task] = None
        self._health_check_interval = 30
        
        # 容器管理
        self.container = RedFireContainer.create_for_service(service_name)
        
        # 统计信息
        self._total_ticks = 0
        self._total_bars = 0
        self._start_time = datetime.now()
    
    async def add_gateway(self, 
                         gateway: RedFireGatewayAdapter, 
                         config: GatewayConfig) -> bool:
        """
        添加网关
        
        Args:
            gateway: 网关适配器实例
            config: 网关配置
            
        Returns:
            bool: 添加是否成功
        """
        try:
            gateway_name = config.name
            
            if gateway_name in self._gateways:
                self.logger.warning(f"网关 {gateway_name} 已存在，将被替换")
                await self.remove_gateway(gateway_name)
            
            # 添加网关
            self._gateways[gateway_name] = gateway
            self._gateway_configs[gateway_name] = config
            self._gateway_status[gateway_name] = GatewayStatus(
                name=gateway_name,
                type=config.type,
                status=gateway.get_status(),
                connected=gateway.is_connected(),
                last_heartbeat=datetime.now()
            )
            
            # 设置回调函数
            gateway.add_tick_callback(self._on_tick)
            gateway.add_bar_callback(self._on_bar)
            gateway.add_contract_callback(self._on_contract)
            gateway.add_status_callback(lambda status, gw=gateway_name: self._on_gateway_status_change(gw, status))
            
            self.logger.info(f"网关 {gateway_name} 添加成功")
            return True
            
        except Exception as e:
            self.logger.error(f"添加网关失败: {e}")
            return False
    
    async def remove_gateway(self, gateway_name: str) -> bool:
        """
        移除网关
        
        Args:
            gateway_name: 网关名称
            
        Returns:
            bool: 移除是否成功
        """
        try:
            if gateway_name not in self._gateways:
                self.logger.warning(f"网关 {gateway_name} 不存在")
                return False
            
            gateway = self._gateways[gateway_name]
            
            # 断开连接
            if gateway.is_connected():
                await gateway.disconnect()
            
            # 清理订阅
            subscribed_symbols = self._gateway_subscriptions.get(gateway_name, set())
            for symbol in subscribed_symbols:
                self._symbol_subscriptions[symbol].discard(gateway_name)
                if not self._symbol_subscriptions[symbol]:
                    del self._symbol_subscriptions[symbol]
            
            # 移除网关
            del self._gateways[gateway_name]
            del self._gateway_configs[gateway_name]
            del self._gateway_status[gateway_name]
            self._gateway_subscriptions.pop(gateway_name, None)
            
            self.logger.info(f"网关 {gateway_name} 移除成功")
            return True
            
        except Exception as e:
            self.logger.error(f"移除网关失败: {e}")
            return False
    
    async def connect_all(self) -> Dict[str, bool]:
        """
        连接所有网关
        
        Returns:
            Dict[str, bool]: 每个网关的连接结果
        """
        results = {}
        
        for gateway_name, gateway in self._gateways.items():
            config = self._gateway_configs[gateway_name]
            
            if not config.enabled:
                self.logger.info(f"网关 {gateway_name} 已禁用，跳过连接")
                results[gateway_name] = False
                continue
            
            try:
                result = await gateway.connect()
                results[gateway_name] = result
                
                if result:
                    self.logger.info(f"网关 {gateway_name} 连接成功")
                else:
                    self.logger.error(f"网关 {gateway_name} 连接失败")
                    
            except Exception as e:
                self.logger.error(f"网关 {gateway_name} 连接异常: {e}")
                results[gateway_name] = False
        
        return results
    
    async def disconnect_all(self) -> Dict[str, bool]:
        """
        断开所有网关连接
        
        Returns:
            Dict[str, bool]: 每个网关的断开结果
        """
        results = {}
        
        for gateway_name, gateway in self._gateways.items():
            try:
                result = await gateway.disconnect()
                results[gateway_name] = result
                
                if result:
                    self.logger.info(f"网关 {gateway_name} 断开成功")
                else:
                    self.logger.error(f"网关 {gateway_name} 断开失败")
                    
            except Exception as e:
                self.logger.error(f"网关 {gateway_name} 断开异常: {e}")
                results[gateway_name] = False
        
        return results
    
    async def subscribe_tick(self, symbol: str, exchange: str = "") -> Dict[str, bool]:
        """
        订阅Tick数据（所有可用网关）
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            
        Returns:
            Dict[str, bool]: 每个网关的订阅结果
        """
        results = {}
        
        for gateway_name, gateway in self._gateways.items():
            if not gateway.is_connected():
                continue
            
            try:
                result = await gateway.subscribe_tick(symbol, exchange)
                results[gateway_name] = result
                
                if result:
                    self._symbol_subscriptions[symbol].add(gateway_name)
                    self._gateway_subscriptions[gateway_name].add(symbol)
                    self.logger.info(f"网关 {gateway_name} 订阅 {symbol} Tick成功")
                else:
                    self.logger.error(f"网关 {gateway_name} 订阅 {symbol} Tick失败")
                    
            except Exception as e:
                self.logger.error(f"网关 {gateway_name} 订阅 {symbol} Tick异常: {e}")
                results[gateway_name] = False
        
        return results
    
    async def subscribe_bar(self, symbol: str, exchange: str = "", interval: str = "1m") -> Dict[str, bool]:
        """
        订阅K线数据（所有可用网关）
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            interval: K线周期
            
        Returns:
            Dict[str, bool]: 每个网关的订阅结果
        """
        results = {}
        
        for gateway_name, gateway in self._gateways.items():
            if not gateway.is_connected():
                continue
            
            try:
                result = await gateway.subscribe_bar(symbol, exchange, interval)
                results[gateway_name] = result
                
                if result:
                    bar_key = f"{symbol}_{interval}"
                    self._symbol_subscriptions[bar_key].add(gateway_name)
                    self._gateway_subscriptions[gateway_name].add(bar_key)
                    self.logger.info(f"网关 {gateway_name} 订阅 {symbol} {interval}K线成功")
                else:
                    self.logger.error(f"网关 {gateway_name} 订阅 {symbol} {interval}K线失败")
                    
            except Exception as e:
                self.logger.error(f"网关 {gateway_name} 订阅 {symbol} {interval}K线异常: {e}")
                results[gateway_name] = False
        
        return results
    
    def get_gateway(self, gateway_name: str) -> Optional[RedFireGatewayAdapter]:
        """获取指定网关"""
        return self._gateways.get(gateway_name)
    
    def get_connected_gateways(self) -> List[str]:
        """获取已连接的网关列表"""
        return [name for name, gateway in self._gateways.items() if gateway.is_connected()]
    
    def get_gateway_status(self, gateway_name: str = None) -> Dict[str, Any]:
        """
        获取网关状态信息
        
        Args:
            gateway_name: 网关名称，为None时返回所有网关状态
            
        Returns:
            Dict[str, Any]: 状态信息
        """
        if gateway_name:
            status = self._gateway_status.get(gateway_name)
            return status.to_dict() if status else {}
        else:
            return {
                name: status.to_dict() 
                for name, status in self._gateway_status.items()
            }
    
    def get_subscriptions(self) -> Dict[str, Any]:
        """获取订阅信息"""
        return {
            "symbol_subscriptions": {
                symbol: list(gateways) 
                for symbol, gateways in self._symbol_subscriptions.items()
            },
            "gateway_subscriptions": {
                gateway: list(symbols) 
                for gateway, symbols in self._gateway_subscriptions.items()
            }
        }
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取统计信息"""
        uptime = (datetime.now() - self._start_time).total_seconds()
        
        return {
            "total_gateways": len(self._gateways),
            "connected_gateways": len(self.get_connected_gateways()),
            "total_subscriptions": sum(len(symbols) for symbols in self._gateway_subscriptions.values()),
            "total_ticks": self._total_ticks,
            "total_bars": self._total_bars,
            "uptime": uptime,
            "ticks_per_second": self._total_ticks / uptime if uptime > 0 else 0,
            "bars_per_second": self._total_bars / uptime if uptime > 0 else 0
        }
    
    # 回调函数管理
    def add_tick_callback(self, callback: Callable[[MarketDataTick], None]):
        """添加Tick数据回调函数"""
        if callback not in self._tick_callbacks:
            self._tick_callbacks.append(callback)
    
    def add_bar_callback(self, callback: Callable[[MarketDataBar], None]):
        """添加K线数据回调函数"""
        if callback not in self._bar_callbacks:
            self._bar_callbacks.append(callback)
    
    def add_contract_callback(self, callback: Callable[[ContractInfo], None]):
        """添加合约信息回调函数"""
        if callback not in self._contract_callbacks:
            self._contract_callbacks.append(callback)
    
    def add_status_callback(self, callback: Callable[[str, ConnectionStatus], None]):
        """添加状态变化回调函数"""
        if callback not in self._status_callbacks:
            self._status_callbacks.append(callback)
    
    # 内部事件处理
    async def _on_tick(self, tick: MarketDataTick):
        """处理Tick数据事件"""
        self._total_ticks += 1
        
        # 更新网关状态
        if tick.gateway in self._gateway_status:
            status = self._gateway_status[tick.gateway]
            status.total_messages += 1
            status.last_heartbeat = datetime.now()
        
        # 分发给回调函数
        for callback in self._tick_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(tick)
                else:
                    callback(tick)
            except Exception as e:
                self.logger.error(f"Tick回调函数执行失败: {e}")
    
    async def _on_bar(self, bar: MarketDataBar):
        """处理K线数据事件"""
        self._total_bars += 1
        
        # 更新网关状态
        if bar.gateway in self._gateway_status:
            status = self._gateway_status[bar.gateway]
            status.total_messages += 1
            status.last_heartbeat = datetime.now()
        
        # 分发给回调函数
        for callback in self._bar_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(bar)
                else:
                    callback(bar)
            except Exception as e:
                self.logger.error(f"K线回调函数执行失败: {e}")
    
    async def _on_contract(self, contract: ContractInfo):
        """处理合约信息事件"""
        # 分发给回调函数
        for callback in self._contract_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(contract)
                else:
                    callback(contract)
            except Exception as e:
                self.logger.error(f"合约信息回调函数执行失败: {e}")
    
    async def _on_gateway_status_change(self, gateway_name: str, status: ConnectionStatus):
        """处理网关状态变化事件"""
        if gateway_name in self._gateway_status:
            gateway_status = self._gateway_status[gateway_name]
            gateway_status.status = status
            gateway_status.connected = (status == ConnectionStatus.CONNECTED)
            gateway_status.last_heartbeat = datetime.now()
            
            if status == ConnectionStatus.ERROR:
                gateway_status.failure_count += 1
        
        # 分发给回调函数
        for callback in self._status_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(gateway_name, status)
                else:
                    callback(gateway_name, status)
            except Exception as e:
                self.logger.error(f"状态变化回调函数执行失败: {e}")
    
    # 监控和健康检查
    async def start_monitoring(self):
        """启动监控任务"""
        if self._monitoring_task and not self._monitoring_task.done():
            return
        
        self._monitoring_task = asyncio.create_task(self._monitoring_loop())
        self.logger.info("网关监控任务已启动")
    
    async def stop_monitoring(self):
        """停止监控任务"""
        if self._monitoring_task and not self._monitoring_task.done():
            self._monitoring_task.cancel()
            try:
                await self._monitoring_task
            except asyncio.CancelledError:
                pass
        
        self.logger.info("网关监控任务已停止")
    
    async def _monitoring_loop(self):
        """监控循环"""
        while True:
            try:
                await self._health_check()
                await asyncio.sleep(self._health_check_interval)
            except asyncio.CancelledError:
                break
            except Exception as e:
                self.logger.error(f"监控循环异常: {e}")
                await asyncio.sleep(5)
    
    async def _health_check(self):
        """健康检查"""
        for gateway_name, gateway in self._gateways.items():
            try:
                config = self._gateway_configs[gateway_name]
                status = self._gateway_status[gateway_name]
                
                # 检查连接状态
                if not gateway.is_connected() and config.enabled:
                    if config.auto_reconnect and status.failure_count < config.max_failure_count:
                        self.logger.info(f"尝试重连网关: {gateway_name}")
                        await gateway.connect()
                
                # 更新运行时间
                status.uptime = (datetime.now() - self._start_time).total_seconds()
                
            except Exception as e:
                self.logger.error(f"网关 {gateway_name} 健康检查失败: {e}")
    
    # 上下文管理器支持
    @asynccontextmanager
    async def lifecycle(self):
        """生命周期管理上下文"""
        try:
            await self.connect_all()
            await self.start_monitoring()
            yield self
        finally:
            await self.stop_monitoring()
            await self.disconnect_all()
    
    def __repr__(self) -> str:
        return f"<RedFireGatewayManager(gateways={len(self._gateways)}, connected={len(self.get_connected_gateways())})>"
